class_name Bullet
extends Node2D



## 子弹是否在达到最大射程时显示残留效果
@export var display_residual_effect_beyond_range: bool = false
## 子弹是否具有穿透效果
@export var can_penetrate: bool = false
## 通过添加bullet_residual_effect节点来实现子弹命中时的效果，若未指定该节点则无残留效果
@export var residual_effect: BulletResidualEffect

@export_group("damage attribute effect")
## 通过添加damage_attribute_effect节点来实现不同伤害属性的可视化效果，若未指定对应节点则无可视化效果
@export var fire_attr_effect: Node2D
## 通过添加damage_attribute_effect节点来实现不同伤害属性的可视化效果，若未指定对应节点则无可视化效果
@export var ice_attr_effect: Node2D
## 通过添加damage_attribute_effect节点来实现不同伤害属性的可视化效果，若未指定对应节点则无可视化效果
@export var thunder_attr_effect: Node2D

@onready var damage_sender: DamageSender = $DamageSender
@onready var sprite: Sprite2D = $Sprite2D


var speed: float
var fly_range: float
var start_pos: Vector2
var direction: Vector2
var hit_effect_op: ObjectPool
var _flying: bool = false


signal expired()


func _ready() -> void:
    damage_sender.hit.connect(
        func(info: DamageInfo, pos: Vector2) -> void:
            _hit_target(info.target, pos)
    )


func _process(_delta: float) -> void:
    if not _flying: return

    _fly_trace()


## virtual，子弹失效
func _expire() -> void:
    ObjectPool.release_obj(self)
    expired.emit()


func _show_hit_effect(pos: Vector2) -> BulletHitEffect:
    var effect: BulletHitEffect
    if hit_effect_op:
        effect = hit_effect_op.acquire() as BulletHitEffect
        effect.global_position = pos
        effect.setup({
            "attr_color": damage_sender.damage_info.get_damage_attribute_color(),
        })
        effect.z_index = z_index + 1
        effect.display()
    return effect


## virtual, 命中目标 [br]
## 显示命中效果和残留效果。若子弹可以贯穿敌人，则不显示残留效果
func _hit_target(target: Character, pos: Vector2) -> void:
    if not can_penetrate: _flying = false

    if not hit_effect_op and not residual_effect and not can_penetrate:
        _expire()
        return
    
    damage_sender.disabled = not can_penetrate

    if not can_penetrate:
        if hit_effect_op and not residual_effect: sprite.hide()

        var h_effect: BulletHitEffect = _show_hit_effect(pos)
        
        if residual_effect:
            residual_effect.display(target)
            await residual_effect.finished
        elif h_effect: await h_effect.finished

        if h_effect: hit_effect_op.release(h_effect)
        _expire()
    
    else:
        var h_effect: BulletHitEffect = _show_hit_effect(pos)
        if h_effect:
            await h_effect.finished
            hit_effect_op.release(h_effect)


## virtual, 飞行轨迹
func _fly_trace() -> void:
    if global_position.distance_squared_to(start_pos) > fly_range ** 2:
        _flying = false
        if display_residual_effect_beyond_range and residual_effect: 
            residual_effect.display()
            await residual_effect.finished
        _expire()
    
    global_position += speed * direction * get_process_delta_time()



func _set_fire_attribute_vfx() -> void:
    pass


func _set_ice_attribute_vfx() -> void:
    pass


func _set_thunder_attribute_vfx() -> void:
    pass


func setup(damage_info: DamageInfo, speed_: float, fly_range_: float, start_pos_: Vector2, direction_: Vector2, hit_effect_op_: ObjectPool) -> void:
    speed = speed_
    fly_range = fly_range_
    start_pos = start_pos_
    global_position = start_pos_
    direction = direction_
    rotation = direction_.angle()
    hit_effect_op = hit_effect_op_

    damage_sender.damage_info = damage_info
    # damage_sender.damage_info.attachment["bullet"] = self
    damage_sender.damage_info.max_handled_count = -1 if can_penetrate else damage_info.max_handled_count

    _flying = true
    damage_sender.disabled = false
    modulate.a = 1
    sprite.show()
